#include "PlayerTank.hpp"
#include "InputManager.hpp"
#include "UserData.hpp"
#include <cmath>
#include <boost/bind.hpp>


PlayerTank::PlayerTank():
Tank(),
m_events()
{	
	// events to check later in function update
	m_events["forward"] = InputEvent(PRESSED_EVENT_TYPE,sf::Key::Z);
	m_events["backward"] = InputEvent(PRESSED_EVENT_TYPE,sf::Key::S);
	m_events["left"] = InputEvent(PRESSED_EVENT_TYPE,sf::Key::Q);
	m_events["right"] = InputEvent(PRESSED_EVENT_TYPE,sf::Key::D);
	m_events["shoot"] = InputEvent(TRIGGERED_PRESSED_EVENT_TYPE,sf::Mouse::Left);

	// create user data
	UserData *ud = new UserData();
	ud->type = "tank";
	ud->ID = 2;
	ud->callback = boost::bind(&PlayerTank::hasBeenHit, this, _1);
	m_body->SetUserData(static_cast<void*>(ud));
}

void PlayerTank::update()
{
	static int first2 = 0; // only one instance
	static int first = 0;;
	// MOVE
	if(CHECK_EVENT(m_events["forward"]))
	{
		// compute direction
		b2Vec2 direction(0.f,-1.f);	
		
		b2Vec2 temp = direction;                          //rotate
		double theta  = -M_PI * float(m_indexGround) / 16.f;
		direction.x = temp.x * cos(theta) - temp.y * sin(theta);
		direction.y = temp.x * sin(theta) + temp.y * cos(theta);

		direction.Normalize();
		if(checkCollision("forward",direction))
			m_body->SetLinearVelocity(2.f * direction);
	}

	else if(CHECK_EVENT(m_events["backward"]))
	{
		// compute direction
		b2Vec2 direction(0.f,-1.f);	
		
		b2Vec2 temp = direction;                          //rotate
		float theta  = -M_PI * float(m_indexGround) / 16.f;
		direction.x = temp.x * cos(theta) - temp.y * sin(theta);
		direction.y = temp.x * sin(theta) + temp.y * cos(theta);
		
		direction.Normalize();
		if(checkCollision("backward",-direction))
			m_body->SetLinearVelocity(-2.f*direction);
	}
	// stop the tank 
	else 
		m_body->SetLinearVelocity(b2Vec2());

	if(CHECK_EVENT(m_events["left"]))
	{
		if(first2 == 0)
		{

		if(m_indexGround == 0)
			m_indexGround = 31;
		else 
			m_indexGround--;

		first2++;
		}
		else first2++;
		if(first2 == 4) first2=0;
	}
	if(CHECK_EVENT(m_events["right"]))
	{
		if(first == 0)
		{
		if(m_indexGround == 31)
			m_indexGround = 0;
		else 
			m_indexGround++;
			first++;
		}
		else first++;
		
		if(first == 4)
			first =0;
	}
	
	// update position
	m_position.x = 40.f * m_body->GetPosition().x;
	m_position.y = 600.f - 40.f * m_body->GetPosition().y;


	// update cannon
	m_indexCannon = computeIndexCannon(InputManager::instance().posMouse());
	
	//shoot
	if(CHECK_EVENT(m_events["shoot"]))
	{
		
	}
}

void PlayerTank::hasBeenHit(const std::string& type)
{
	if(type == "bullet" && m_life > 0) 
		m_life--;		
}


unsigned int PlayerTank::computeIndexCannon(const sf::Vector2i& posMouse)
{	
	b2Vec2 direction;
	direction.x = posMouse.x - m_position.x;
	direction.y = posMouse.y - m_position.y;
	direction.Normalize();
	float theta2 = acos(direction.x);

	float theta3 = asin(direction.y);
	theta2 = theta2*180.f/M_PI;
	theta3 = theta3*180.f/M_PI;
	theta3+=90;
	theta2+=90;
	float theta = theta2;
/*	if(theta2 != theta3)
		theta = -theta;
	theta = theta*180.f/M_PI;
	theta += 90;*/
	LogInfo << theta2 << "   " << theta3 << LogEnd;
	return 0;
}


bool PlayerTank::checkCollision(const std::string& way,const b2Vec2 &direction)
{
    class RayCastClosestCallback : public b2RayCastCallback
    {
    public:
        RayCastClosestCallback()
        {
            m_hit = false;
        }

        float32 ReportFixture(	b2Fixture* fixture, const b2Vec2& point,
            const b2Vec2& normal, float32 fraction)
        {
            UserData *ud = static_cast<UserData*>(fixture->GetBody()->GetUserData());
            if(ud->ID == 2)
                return -1;
            m_hit = true;
            m_point = point;
            m_normal = normal;
            return fraction;
        }

        bool m_hit;
        b2Vec2 m_point;
        b2Vec2 m_normal;
    };
    
	if(way == "forward")
	{
		b2Vec2 p = m_body->GetPosition();
		b2Vec2 p2 = p + direction;
    	RayCastClosestCallback callback;
    	PhysicEngine::instance().world()->RayCast(&callback,p,p2);
    	return !callback.m_hit;
	}
	else if(way == "backward")
	{
		return true;
	}
	
	else 
		return true;
}
